package com.mingtu.jgspatrol.utils;

import static com.mingtu.jgspatrol.utils.MyConstant.LEFT_TOP_LOCATION;
import static com.mingtu.jgspatrol.utils.MyConstant.MAX_ZOOM;
import static com.mingtu.jgspatrol.utils.MyConstant.MIN_ZOOM;
import static com.mingtu.jgspatrol.utils.MyConstant.RIGHT_BOTTOM_LOCATION;

import android.os.Environment;

import com.blankj.utilcode.util.FileUtils;
import com.blankj.utilcode.util.SPStaticUtils;
import com.blankj.utilcode.util.StringUtils;
import com.blankj.utilcode.util.ToastUtils;
import com.mingtu.common.utils.Constant;
import com.mingtu.common.utils.MyLogUtil;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 地图瓦片工具类
 * 用于处理地图瓦片的坐标计算和存储空间检查
 * 
 * @Author : wkk
 * @Date : 2024-7-2 16:22:41
 * @Email : 1281573890@qq.com
 */
public class TileStrUtils {

    private static final String TAG = "TileStrUtils";
    private static final String MB_SUFFIX = "MB";
    private static final String TILE_SEPARATOR = "_";
    private static final String TILE_LIST_SEPARATOR = ",";
    private static final double MB_TO_BYTES = 1024 * 1024;
    
    private static volatile TileStrUtils instance;
    private final ExecutorService executorService;
    
    // 缓存从 SharedPreferences 读取的值
    private String xyzZoomLeftTop;
    private String xyzZoomRightBottom;
    private String myXyzZoom;

    private TileStrUtils() {
        this.executorService = Executors.newSingleThreadExecutor();
        loadCachedValues();
    }

    /**
     * 获取单例实例
     * 使用双重检查锁定确保线程安全
     */
    public static TileStrUtils getInstance() {
        if (instance == null) {
            synchronized (TileStrUtils.class) {
                if (instance == null) {
                    instance = new TileStrUtils();
                }
            }
        }
        return instance;
    }

    /**
     * 加载缓存的值
     */
    private void loadCachedValues() {
        xyzZoomLeftTop = SPStaticUtils.getString(MySPTools.XYZOOM_LEFTTOP);
        xyzZoomRightBottom = SPStaticUtils.getString(MySPTools.XYZOOM_RIGHTBOTTOM);
        myXyzZoom = SPStaticUtils.getString(MySPTools.XYZOOM);
    }

    /**
     * 获取瓦片坐标数据
     */
    public void getTileXYZoomData() {
        if (shouldGenerateTileData()) {
            executorService.execute(this::generateTileData);
        }
    }

    /**
     * 判断是否需要生成瓦片数据
     */
    private boolean shouldGenerateTileData() {
        return StringUtils.isEmpty(myXyzZoom) || 
               StringUtils.isEmpty(xyzZoomLeftTop) || 
               StringUtils.isEmpty(xyzZoomRightBottom) ||
               !myXyzZoom.contains(xyzZoomLeftTop) || 
               !myXyzZoom.contains(xyzZoomRightBottom);
    }

    /**
     * 根据经纬度和缩放级别计算瓦片坐标
     */
    private double[] getXYByLnglat(double lng, double lat, int level) {
        double n = Math.pow(2, level);
        double xtile = n * ((lng + 180) / 360);
        double latRad = Math.toRadians(lat);
        double ytile = n * (1 - (Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI)) / 2;

        return new double[]{xtile, ytile};
    }

    /**
     * 获取左上角瓦片坐标
     */
    private double[] getLeftTop(int level) {
        return getXYByLnglat(LEFT_TOP_LOCATION[0], LEFT_TOP_LOCATION[1], level);
    }

    /**
     * 获取右下角瓦片坐标
     */
    private double[] getRightBottom(int level) {
        return getXYByLnglat(RIGHT_BOTTOM_LOCATION[0], RIGHT_BOTTOM_LOCATION[1], level);
    }

    /**
     * 生成瓦片数据
     */
    private void generateTileData() {
        MyLogUtil.d(TAG, "开始生成瓦片数据");
        
        StringBuilder xyzZoomBuilder = new StringBuilder();
        
        for (int zoom = MIN_ZOOM; zoom <= MAX_ZOOM; zoom++) {
            double[] leftTopXY = getLeftTop(zoom);
            double[] rightBottomXY = getRightBottom(zoom);
            
            for (int x = (int) leftTopXY[0]; x <= (int) rightBottomXY[0]; x++) {
                for (int y = (int) leftTopXY[1]; y <= (int) rightBottomXY[1]; y++) {
                    xyzZoomBuilder.append(zoom)
                                 .append(TILE_SEPARATOR)
                                 .append(x)
                                 .append(TILE_SEPARATOR)
                                 .append(y)
                                 .append(TILE_LIST_SEPARATOR);
                    
                    // 保存边界瓦片信息
                    saveBoundaryTileInfo(zoom, x, y, leftTopXY, rightBottomXY);
                }
            }
        }
        
        String xyzZoom = xyzZoomBuilder.toString();
        SPStaticUtils.put(MySPTools.XYZOOM, xyzZoom);
        
        // 更新缓存
        myXyzZoom = xyzZoom;
        
        MyLogUtil.d(TAG, "瓦片数据生成完成");
    }

    /**
     * 保存边界瓦片信息
     */
    private void saveBoundaryTileInfo(int zoom, int x, int y, double[] leftTopXY, double[] rightBottomXY) {
        if (zoom == MIN_ZOOM && x == (int) leftTopXY[0] && y == (int) leftTopXY[1]) {
            String leftTopTile = zoom + TILE_SEPARATOR + x + TILE_SEPARATOR + y;
            SPStaticUtils.put(MySPTools.XYZOOM_LEFTTOP, leftTopTile);
            xyzZoomLeftTop = leftTopTile;
        }
        
        if (zoom == MAX_ZOOM && x == (int) rightBottomXY[0] && y == (int) rightBottomXY[1]) {
            String rightBottomTile = zoom + TILE_SEPARATOR + x + TILE_SEPARATOR + y;
            SPStaticUtils.put(MySPTools.XYZOOM_RIGHTBOTTOM, rightBottomTile);
            xyzZoomRightBottom = rightBottomTile;
        }
    }

    /**
     * 检查有效存储空间
     */
    public void checkEffectiveStorageSpace() {
        if (!isExternalStorageMounted()) {
            ToastUtils.showLong("未获取到外部存储！");
            return;
        }

        try {
            double currentSize = getCurrentTileSize();
            long availableSize = FileUtils.getFsAvailableSize(Constant.TILE_SAVE_PATH);
            
            if (availableSize <= currentSize * MB_TO_BYTES) {
                ToastUtils.showLong("内存不够现在离线地图瓦片，请清理内存！");
            }
        } catch (Exception e) {
            MyLogUtil.e(TAG, "检查存储空间时发生错误：" +  e.toString());
            ToastUtils.showLong("检查存储空间失败");
        }
    }

    /**
     * 检查外部存储是否挂载
     */
    private boolean isExternalStorageMounted() {
        String state = Environment.getExternalStorageState();
        return Environment.MEDIA_MOUNTED.equals(state);
    }

    /**
     * 获取当前瓦片大小（MB）
     */
    private double getCurrentTileSize() {
        String fileSize = FileUtils.getSize(Constant.TILE_SAVE_PATH);
        
        if (StringUtils.isEmpty(fileSize)) {
            return 0.0;
        }
        
        try {
            if (fileSize.contains(MB_SUFFIX)) {
                String sizeStr = fileSize.replace(MB_SUFFIX, "").trim();
                return Double.parseDouble(sizeStr);
            }
        } catch (NumberFormatException e) {
            MyLogUtil.e(TAG, "解析文件大小时发生错误: " + fileSize + "，" + e.toString());
        }
        
        return 0.0;
    }

    /**
     * 释放资源
     */
    public void release() {
        if (executorService != null && !executorService.isShutdown()) {
            executorService.shutdown();
        }
    }
}
